import * as THREE from 'three'
import { FreeThree } from './utils/FreeThree.js'
export const THREE_SCENE_INITIALIZATION = 'THREE_SCENE_INITIALIZATION'
export const THREE_SCENE_DESTROY = 'THREE_SCENE_DESTROY'

export class ThreeScene {
    static instanceMap = new Map()
    static getInstance(name) {
        return this.instanceMap.get(name)
    }
    static setInstance(name, instance) {
        if (this.instanceMap.has(name)) {
            throw new Error(`场景${sceneName}已经存在`)
        }
        this.instanceMap.set(name, instance)
    }
    constructor({ context, inputElement, name }) {
        this.name = name
        this.renderer = new THREE.WebGLRenderer({
            antialias: true,
            ...context,
        })
        this.inputElement = inputElement || context.canvas
        this.scene = new THREE.Scene()
        this.camera = this.createCamera()
        this.clock = new THREE.Clock()
    }
    createCamera() {
        const fov = 45
        const aspect =
            this.inputElement.clientWidth / this.inputElement.clientHeight
        const near = 0.1
        const far = 10000000000
        return new THREE.PerspectiveCamera(fov, aspect, near, far)
    }

    resizeRendererToDisplaySize() {
        const { inputElement, renderer } = this
        const pixelRatio = self.importScripts
            ? inputElement.devicePixelRatio
            : window.devicePixelRatio
        const width = Math.floor(inputElement.clientWidth * pixelRatio)
        const height = Math.floor(inputElement.clientHeight * pixelRatio)

        const canvas = renderer.domElement
        const needResize = canvas.width !== width || canvas.height !== height
        if (needResize) {
            renderer.setSize(width, height, false)
        }
        return needResize
    }

    render() {
        const { renderer, scene, camera, inputElement } = this
        if (this.resizeRendererToDisplaySize()) {
            camera.aspect = inputElement.clientWidth / inputElement.clientHeight
            camera.updateProjectionMatrix()
        }
        renderer.render(scene, camera)
    }

    destroy() {
        FreeThree.disposeObject3D(this.scene)
    }
}
